﻿using System.IO;
using UnityEngine;
using UnityEngine.Networking;

namespace Yoozoo.Modules.Download
{
    public class UnityWebRequestDownload
    {
        FileDownloadHandler fileDownloadHandler;

        public DownloadInfo Info { get; private set; }

        public void Start(DownloadInfo downloadInfo, PreAllocatedBuffer buffer)
        {
            downloadInfo.UnityWebRequestDownload = this;
            downloadInfo.Buffer = buffer;

            Info = downloadInfo;
            Info.State = DownloadState.Downloading;
            fileDownloadHandler = new FileDownloadHandler(buffer.Buffer);
            fileDownloadHandler.SetDownloadInfo(downloadInfo);

            var directoryName = Path.GetDirectoryName(Info.Path);
            if (directoryName == null)
            {
                Info.State = DownloadState.Error;
                return;
            }

            // GC.Alloc 0.9 kb
            if (!Directory.Exists(directoryName))
                // GC.Alloc 3.5 kb
                Directory.CreateDirectory(directoryName);

            // GC.Alloc 1.2kb
            var fileInfo = new FileInfo(Info.Path);
            if (fileInfo.Exists)
                Info.CurrentSize = (ulong)fileInfo.Length;

            if (Info.CurrentSize == Info.TotalSize)
            {
                Info.State = DownloadState.Done;
            }
            else
            {
                // GC.Alloc 8.4kb
                if (!fileDownloadHandler.OpenOrCreateFile())
                {
                    Info.State = DownloadState.Error;
                    fileDownloadHandler.CloseStream();
                }
                else
                {
                    var request = UnityWebRequest.Get(Info.Url);
                    request.timeout = 60;
                    request.redirectLimit = 1;
                    request.downloadHandler = fileDownloadHandler;
                    if (Info.CurrentSize == 0)
                        request.SetRequestHeader("Range", "bytes=0-");
                    else
                        request.SetRequestHeader("Range", "bytes=" + Info.CurrentSize + "-"/* + Info.totalSize*/);
                    var operation = request.SendWebRequest();
                    operation.completed += OnOperationCompleted;
                }
            }
        }

        public void Cancel()
        {
            fileDownloadHandler?.Cancel();
        }

        private void OnOperationCompleted(AsyncOperation asyncOperation)
        {
            var operation = asyncOperation as UnityWebRequestAsyncOperation;
            if (operation == null)
            {
                Info.State = DownloadState.Error;
                Info.ErrorMessage = "asyncOperation == null";
                return;
            }

            var request = operation.webRequest;

            if (request.isNetworkError || request.isHttpError)
            {
                Info.State = DownloadState.Error;
                Info.ErrorMessage = request.error;
            }
            else
            {
                Info.State = DownloadState.Done;
            }
            fileDownloadHandler.Reset();
            request.Dispose();
        }

        public float Progress => (float)((double)Info.CurrentSize / (double)Info.TotalSize);

        public void Reset()
        {
            fileDownloadHandler.Reset();
            Info = null;
        }
    }
}
